/*****************************************************************************
 * ARCHIVO : Hilos.c
 *
 * CONTENIDO : Programa que ilustra la creacion de hilos a nivel de
 *             kernel y a nivel de usuario
 *             
 * AUTOR :  Yudith Cardinale
 * 
 * Modificado por Carlos Figueira para incluir parametros en las
 * funciones llamadas en los pthread_create 
 *
 *
 *****************************************************************************/

#include <sys/types.h>
#include <sys/stat.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include <fcntl.h>
#include <errno.h>

/*  struct p es usado como ejemplo de pase de parametros de tipo
   diferente. En este caso se usan dos argumentos: uno de tipo cadena
   de caracteres, y otro de tipo entero. tipos_dif es usado para
   simplificar las declaraciones
*/ 
struct p {
  char nombre[20];
  int itera;
} ;
typedef struct p Tipos_dif;

/***************************************************************
/* Definicion de la rutina de un thread
 * dormilon: recibe dos parametros enteros, bajo la forma de un
 * arreglo, debido a la definicion de pthread_create
 * arg: debe ser un arreglo de enteros
/***************************************************************/

void *dormilon(void *arg) {
  int * para = (int *) arg;

  printf("dormilon: dormire por %d segundos\n", *para);
  sleep(*para);
  printf("dormilon: me desperte! Mi segundo argumento es %d\n",  *(para+1));
  pthread_exit(0);
}

/***************************************************************
/* Definicion de la rutina de otro thread
 * trabajador:
 * Escribe un mensaje incluyendo una cadena de caracteres pasada como
 *  parametro, un numero de veces indicado en un segundo parametro
 * argumentos:
 *  un struct con dos campos "nombre" e "itera". El primero es el
 mensaje y el segundo es el numero de iteraciones
/***************************************************************/

void *trabajador(void *arg)
{
  int i;
  struct p * est = (struct p *) arg;

  printf("trabajador: debo hacer  %d iteraciones\n", est->itera);
  for (i=0;i<est->itera;i++)
     printf("trabajador: Estoy Trabajando. El mensaje es -- %s --\n", est->nombre);


  pthread_exit(0);
}

/***************************************************************
/*  Rutina principal.
/***************************************************************/

int main(void)
{
  pthread_t t1,t2;
  pthread_attr_t mis_atr;
  int check;  
 
  Tipos_dif dos_param; /* usado en argumentos del trabajador */

  int param_ent[2]; /* usado en argumentos del dormilon */

  param_ent[0]=2;
  param_ent[1]=47;


/***************************************************************
/*  Iniciaiizacion de atributos por defecto.
/***************************************************************/  

  if (pthread_attr_init(&mis_atr)) {
    perror("No se pudo inicializar atributos");
    exit(1);
  }                       

/***************************************************************
/*  Definicion del nivel de los threads.
/***************************************************************/

/***************************************************************
/*  Threads a nivel de usuario.
/***************************************************************/

     pthread_attr_setscope(&mis_atr,PTHREAD_SCOPE_PROCESS);
     printf("Valor de PTHREAD_SCOPE_PROCESS %d\n",PTHREAD_SCOPE_PROCESS);


/***************************************************************
/*  Threads a nivel de kernel. (comentar las dos lineas de arriba
/*  y descomentar las dos de abajo)
/***************************************************************/  

//         pthread_attr_setscope(&mis_atr,PTHREAD_SCOPE_SYSTEM);
//          printf("Valor de PTHREAD_SCOPE_SYSTEM %d\n",PTHREAD_SCOPE_SYSTEM);


/***************************************************************
/*  Creacion de los Threads.
/***************************************************************/

  if (pthread_create(&t1,&mis_atr,dormilon,(void *) param_ent)!=0) {
    fprintf(stderr,"No se pudo crear el thread dormilon:%s\n",strerror(errno));
  }      

  printf("Creado el thread dormilon %d\n",t1);

  dos_param.nombre[0]='\0';
  sprintf(dos_param.nombre,"Prueba");
  dos_param.itera=4;

  if (pthread_create(&t2,&mis_atr,trabajador,(void *) &dos_param)!=0) {
    fprintf(stderr,"No se pudo crear el thread trabajador:%s\n",strerror(errno));
  }      

  printf("Creado el thread trabajador %d\n",t2);

/***************************************************************
/*  Esperando a que los threads terminen.
/***************************************************************/
  pthread_join(t2,NULL);
  printf("Termino  el thread trabajador %d\n",t2);
  pthread_join(t1,NULL);
  printf("Termino el thread dormilon %d\n",t1);
  
/***************************************************************
/*  Verificando que los threads realmente corrieron de kernel o 
/*  de usuario segun el  pthread_attr_setscope
/***************************************************************/
  pthread_attr_getscope(&mis_atr,&check);
  if (check == PTHREAD_SCOPE_PROCESS)
    printf("Los threads son  PTHREAD_SCOPE_PROCESS \n");
  else printf("Los threads son  PTHREAD_SCOPE_SYSTEM \n");
}                  
